package com.cyh.testdesignpattern;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;

import com.cyh.testdesignpattern.adapter.classadapter.Phone;
import com.cyh.testdesignpattern.adapter.classadapter.VoltageAdapter;
import com.cyh.testdesignpattern.adapter.interfaceadapter.AbsAdapter;
import com.cyh.testdesignpattern.adapter.objectadapter.ObjectPhone;
import com.cyh.testdesignpattern.adapter.objectadapter.ObjectVoltage220V;
import com.cyh.testdesignpattern.adapter.objectadapter.ObjectVoltageAdapter;
import com.cyh.testdesignpattern.appearance.HomeTheaterFacade;
import com.cyh.testdesignpattern.bridge.FoldedPhone;
import com.cyh.testdesignpattern.bridge.XiaoMiBrand;
import com.cyh.testdesignpattern.builer.CommonHouse;
import com.cyh.testdesignpattern.builer.HighHouse;
import com.cyh.testdesignpattern.builer.House;
import com.cyh.testdesignpattern.builer.HouseDirector;
import com.cyh.testdesignpattern.chain.CollegeApprover;
import com.cyh.testdesignpattern.chain.DepartmentApprover;
import com.cyh.testdesignpattern.chain.PurchaseRequest;
import com.cyh.testdesignpattern.chain.SchoolApprover;
import com.cyh.testdesignpattern.chain.ViceSchoolApprover;
import com.cyh.testdesignpattern.command.LightOffCommand;
import com.cyh.testdesignpattern.command.LightOnCommand;
import com.cyh.testdesignpattern.command.LightReceiver;
import com.cyh.testdesignpattern.command.RemoteController;
import com.cyh.testdesignpattern.command.TvOffCommand;
import com.cyh.testdesignpattern.command.TvOnCommand;
import com.cyh.testdesignpattern.command.TvReceiver;
import com.cyh.testdesignpattern.composite.College;
import com.cyh.testdesignpattern.composite.Department;
import com.cyh.testdesignpattern.composite.OrganizationComponent;
import com.cyh.testdesignpattern.composite.University;
import com.cyh.testdesignpattern.decorator.Chocolate;
import com.cyh.testdesignpattern.decorator.Drink;
import com.cyh.testdesignpattern.decorator.LongbackCoffe;
import com.cyh.testdesignpattern.decorator.Milk;
import com.cyh.testdesignpattern.factory.absfactory.order.BjFactory;
import com.cyh.testdesignpattern.factory.absfactory.order.LdFactory;
import com.cyh.testdesignpattern.factory.absfactory.order.OrderPizza;
import com.cyh.testdesignpattern.factory.factorymethod.order.BjOrderPizza;
import com.cyh.testdesignpattern.factory.factorymethod.order.LdOrderPizza;
import com.cyh.testdesignpattern.factory.simplefactory.OrderPizza01;
import com.cyh.testdesignpattern.factory.simplefactory.OrderPizza02;
import com.cyh.testdesignpattern.factory.simplefactory.SimpleFactory;
import com.cyh.testdesignpattern.flyweight.User;
import com.cyh.testdesignpattern.flyweight.WebSite;
import com.cyh.testdesignpattern.flyweight.WebSiteFactory;
import com.cyh.testdesignpattern.interpreter.AndExpression;
import com.cyh.testdesignpattern.interpreter.Expression;
import com.cyh.testdesignpattern.interpreter.OrExpression;
import com.cyh.testdesignpattern.interpreter.TerminalExpression;
import com.cyh.testdesignpattern.iterator.OutputImpl;
import com.cyh.testdesignpattern.iterator.TCollege;
import com.cyh.testdesignpattern.iterator.TComputerCollege;
import com.cyh.testdesignpattern.iterator.TInfoCollege;
import com.cyh.testdesignpattern.mediator.Alarm;
import com.cyh.testdesignpattern.mediator.ConcreteMediator;
import com.cyh.testdesignpattern.mediator.Curtains;
import com.cyh.testdesignpattern.mediator.Mediator;
import com.cyh.testdesignpattern.memento.Caretaker;
import com.cyh.testdesignpattern.memento.Originator;
import com.cyh.testdesignpattern.observer.BaiduConditions;
import com.cyh.testdesignpattern.observer.CureentConditions;
import com.cyh.testdesignpattern.observer.WeatherData;
import com.cyh.testdesignpattern.prototype.Sheep;
import com.cyh.testdesignpattern.prototype.deepclone.DeepCloneableTarget;
import com.cyh.testdesignpattern.prototype.deepclone.DeepProtoType;
import com.cyh.testdesignpattern.proxy.cglib.MyProxy;
import com.cyh.testdesignpattern.proxy.cglib.Printer;
import com.cyh.testdesignpattern.proxy.dynamic.ITeacherDy;
import com.cyh.testdesignpattern.proxy.dynamic.ProxyFactory;
import com.cyh.testdesignpattern.proxy.dynamic.TeacherDy;
import com.cyh.testdesignpattern.proxy.staticmode.TeacherDao;
import com.cyh.testdesignpattern.proxy.staticmode.TeacherDaoProxy;
import com.cyh.testdesignpattern.singleton.Singleton05;
import com.cyh.testdesignpattern.state.RaffleAction;
import com.cyh.testdesignpattern.strategy.GoodFlyBehavior;
import com.cyh.testdesignpattern.strategy.PekingDuck;
import com.cyh.testdesignpattern.strategy.ToyDuck;
import com.cyh.testdesignpattern.strategy.WildDuck;
import com.cyh.testdesignpattern.template.PeanutSoyaMilk;
import com.cyh.testdesignpattern.template.PureSoyaMilk;
import com.cyh.testdesignpattern.template.RedBeanSoyaMilk;
import com.cyh.testdesignpattern.template.SoyaMilk;
import com.cyh.testdesignpattern.visitor.Fail;
import com.cyh.testdesignpattern.visitor.Man;
import com.cyh.testdesignpattern.visitor.ObjectStructure;
import com.cyh.testdesignpattern.visitor.Success;
import com.cyh.testdesignpattern.visitor.Woman;

import java.util.ArrayList;
import java.util.List;

/**
 * 设计模式
 * 设计模式的作用：1）代码重用性。2）可读性。3）可扩展性。4）可靠性。5）使程序呈现高内聚，低耦合的特性。
 * 1：设计模式的七大原则：
 *    1）单一职责原则：类的职责单一，方法的职责单一
 *    2）接口隔离原则：例如一个接口有5个方法，但是a只用到其中3个，b用到其它的两个。我们可以将这个接口分成两个接口，达到隔离目的。
 *    3）依赖倒转原则：如函数参数应该传接口，而不应该传类。
 *       a.高层模块不应该依赖低层模块，二者都应该依赖抽象
 *       b.抽象不应该依赖细节，细节应该依赖抽象
 *       c.依赖倒转（倒置）的中心思想是面向接口编程
 *    4）里氏替换原则
 *       a.继承有一个缺点，如果父类中某个方法很重要，不能随便继承去修改这个方法。 那怎么去使用继承呢？=》里氏替换原则
 *       b.里氏替换原则是在子类中尽量不要重写父类的方法。在适当情况下，可以通过聚合、组合、依赖来解决问题。
 *       c.解决方法，a是一个接口，不要放这个重要的方法，b是接口a的实现类，加入这个重要这个方法。c也是a的实现类，并且里面有b的对象，这个对象就可以调用重要方法了。
 *    5）开闭原则： 对扩展开放，对修改关闭。---简称ocp: 最基本最重要的原则。
 *        a.比如画三角形、矩形、圆形时只需要在同一个方法中执行，而不应该分成三个方法，传进来的参数应该是父类， 子类去实现这个方法，如果还有其他图形，只需要增加一个类。
 *    6）迪米特法则：又叫最少知道原则：一个对象应该对其他对象保持最少的了解；类与类关系越密切，耦合度越大。
 *         即一个类对自己依赖的类知道越少越好。也就是对外提供public越少越好。
 *         也就是只与直接朋友通信。
 *         什么是直接朋友：成员变量、方法参数、方法返回值都是直接朋友。而方法里面的局部变量不是。所以方法里面尽量少用局部变量。
 *         比如: 类a中的方法中有参数朋友对象b, b对象获得c对象数据，在方法中对数据处理，这种方式是不对的。应该是b调用方法在b中的方法来处理数据。即：自己类的方法只干自己类的事情。
 *    7）合成复用原则：原则是尽量使用组合/聚合的方式，而不是使用继承。
 *          即：在a类中一个成员变量是b类的一个对象；或者a类的一个方法的参数是b类的一个对象。
 *          聚合关系：定义成员变量时，没有新建对象，而是在某个方法中传过这个对象赋值给成员变量。
 *          组合关系：定义成员变量时新建new对象。
 *          依赖关系：
 *          泛化关系：
 *          实现关系：
 *          关联关系：
 *
 * 2：设计模式的类型
 *   1）创建型模式：单例模式、抽象工厂模式、原型模式、构建者模式、工厂模式
 *   2）结构型模式：适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
 *   3）行为型模式：模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、
 *                备忘录模式、解释器模式（Interpreter模式）、状态模式、策略模式、职责链模式（责任链模式）
 *
 * */
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    //单例模式（写了7种）
    public void onClick01(View view) {
        Singleton05 s01 = Singleton05.getInstance();
        Singleton05 s02 = Singleton05.getInstance();
        if(s01 == s02) {
            Log.i("MainActivity", "验证单例模式成功");
        }
    }
    //简单工厂模式（非静态方式）
    public void onClick02(View view) {
        SimpleFactory simpleFactory = new SimpleFactory();
        OrderPizza01 orderPizza01 = new OrderPizza01();
        orderPizza01.setFactory(simpleFactory, "gree");
    }

    //简单工厂模式（静态方式）
    public void onClick03(View view) {
        OrderPizza02 orderPizza02 = new OrderPizza02();
        orderPizza02.setFactory("cheese");
    }

    //工厂方法模式
    public void onClick04(View view) {
        BjOrderPizza bjOrderPizza_gree = new BjOrderPizza("gree");
        BjOrderPizza bjOrderPizza_cheese = new BjOrderPizza("cheese");
        LdOrderPizza ldOrderPizza_gree = new LdOrderPizza("gree");
        LdOrderPizza ldOrderPizza_cheese = new LdOrderPizza("cheese");
    }

    //抽象工厂模式
    public void onClick05(View view) {
        new OrderPizza(new LdFactory(), "gree");
        new OrderPizza(new LdFactory(), "cheese");
        new OrderPizza(new BjFactory(), "gree");
        new OrderPizza(new BjFactory(), "cheese");

    }

    //原型模式 克隆模式 prototype (浅拷贝)
    public void onClick06(View view) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        sheep.friend = new Sheep("jack", 2, "黑色");
        Sheep sheep1 = (Sheep) sheep.clone();
        Log.i("MainActivity", sheep.toString());
        Log.i("MainActivity", sheep1.toString());
        Log.i("MainActivity", "" + (sheep == sheep1));
        Log.i("MainActivity", "" + (sheep.friend == sheep1.friend));

    }

    //原型模式 -- 深拷贝
    public void onClick07(View view) throws CloneNotSupportedException {
        DeepProtoType p = new DeepProtoType();
        p.name = "cyh";
        p.deepCloneableTarget = new DeepCloneableTarget("gyq", "ybz");

        //方式一完成深拷贝
        DeepProtoType p2 = (DeepProtoType) p.clone();
        Log.i("MainActivity", p.toString());
        Log.i("MainActivity", p2.toString());
        Log.i("MainActivity", "" + (p == p2));
        Log.i("MainActivity", "" + (p.deepCloneableTarget == p2.deepCloneableTarget));

        //方式二完成深拷贝（推荐）
        DeepProtoType p3 = (DeepProtoType) p.deepClone();
        Log.i("MainActivity", p.toString());
        Log.i("MainActivity", p3.toString());
        Log.i("MainActivity", "" + (p == p3));
        Log.i("MainActivity", "" + (p.deepCloneableTarget == p3.deepCloneableTarget));

    }

    //建造者模式---builder
    public void onClick08(View view) {
        CommonHouse commonHouse = new CommonHouse("普通地基", "普通墙", "普通顶");
        HouseDirector houseDirector = new HouseDirector(commonHouse);
        houseDirector.setHouseBuilder(commonHouse);
        House house = houseDirector.constructHouse();
        Log.i("MainActivity", house.toString());


        HighHouse highHouse = new HighHouse("高层地基", "高层墙", "高层顶");
        houseDirector = new HouseDirector(highHouse);
        houseDirector.setHouseBuilder(highHouse);
        house = houseDirector.constructHouse();
        Log.i("MainActivity", house.toString());


    }

    //适配器模式---adapter---类适配器
    public void onClick09(View view) {
        Phone phone = new Phone();
        phone.charging(new VoltageAdapter());

    }

    //适配器模式---对象适配器
    public void onClick10(View view) {
        ObjectPhone phone = new ObjectPhone();
        phone.charging(new ObjectVoltageAdapter(new ObjectVoltage220V()));

    }

    //适配器模式---接口适配器
    public void onClick11(View view) {
        AbsAdapter absAdapter = new AbsAdapter(){
            @Override
            public void m1() {
                Log.i("MainActivity", "只需要实现我们所关心的方法");
            }
        };
        absAdapter.m1();

    }

    //桥接模式--bridge
    public void onClick12(View view) {
        //获取手机（样式+品牌）
        FoldedPhone foldedPhone = new FoldedPhone(new XiaoMiBrand());
        foldedPhone.open();
        foldedPhone.call();
        foldedPhone.close();
    }

    //装饰者模式--decorator
    public void onClick13(View view) {
        //先点一份美式咖啡
        Drink order = new LongbackCoffe();
        //打印单品的美式咖啡的价格，这一步没有经过装饰者
        Log.i("MainActivity", "描述：" + order.getDes() + ", 总费用：" + order.cost());
        //加入一份牛奶
        order = new Milk(order);
        Log.i("MainActivity", "描述：" + order.getDes() + ", 总费用：" + order.cost());
        //加入一份巧克力
        order = new Chocolate(order);
        Log.i("MainActivity", "描述：" + order.getDes() + ", 总费用：" + order.cost());
    }

    //组合模式--composite
    public void onClick14(View view) {
        //学校
        OrganizationComponent university = new University("清华大学", "没考上");

        //院系
        OrganizationComponent computerCollege = new College("计算机学院", "电脑");
        OrganizationComponent infoCollege = new College("信息工程学院", "通信");

        //专业
        OrganizationComponent sortDepartment = new Department("软件工程", "软的");
        OrganizationComponent netDepartment = new Department("网络工程", "无的");
        OrganizationComponent infoDepartment = new Department("电子信息工程", "我的");

        computerCollege.add(sortDepartment);
        computerCollege.add(netDepartment);
        infoCollege.add(infoDepartment);
        university.add(computerCollege);
        university.add(infoCollege);

        university.print();

    }

    //外观模式--appearance
    public void onClick15(View view) {
        HomeTheaterFacade facade = new HomeTheaterFacade();
        facade.ready();
        facade.play();
        facade.pause();
        facade.end();
    }

    //享元模式--flyweight
    public void onClick16(View view) {
        WebSiteFactory webSiteFactory  = new WebSiteFactory();
        WebSite webSite1  = webSiteFactory.getWebSiteCategory("新闻");
        webSite1.use(new User("tom"));
        WebSite webSite2  = webSiteFactory.getWebSiteCategory("博客");
        webSite2.use(new User("jack"));
        WebSite webSite3  = webSiteFactory.getWebSiteCategory("博客");
        webSite3.use(new User("jojo"));
        Log.i("MainActivity", "一共创建了多少个对象：" + webSiteFactory.getWebSiteCount()); //2个
    }

    //代理模式--proxy--staticmode--静态代理
    public void onClick17(View view) {
        TeacherDao teacherDao = new TeacherDao();
        TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
        teacherDaoProxy.teach();
    }

    //代理模式--proxy--dynamic--动态jdk代理
    public void onClick18(View view) {
        ITeacherDy target = new TeacherDy();
        ITeacherDy proxyInstance = (ITeacherDy) new ProxyFactory(target).getProxyInstance();
        Log.i("MainActivity", "代理类型：" + proxyInstance.getClass());
        proxyInstance.teach();

    }

    //代理模式--proxy--cglib--动态cglib代理(不需要接口)
    public void onClick19(View view) {
        Printer printer = (Printer) new MyProxy(this).getProxy(Printer.class);
        printer.print();
    }

    //模板模式--template
    public void onClick20(View view) {
        SoyaMilk red = new RedBeanSoyaMilk();
        red.make();
        Log.i("MainActivity", "---------------");
        SoyaMilk peanut = new PeanutSoyaMilk();
        peanut.make();
        Log.i("MainActivity", "---------------");
        SoyaMilk pure = new PureSoyaMilk();
        pure.make();
    }

    //命令模式--command
    public void onClick21(View view) {
        LightReceiver lightReceiver = new LightReceiver();
        LightOnCommand lightOnCommand  = new LightOnCommand(lightReceiver);
        LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);

        RemoteController remoteController = new RemoteController();

        remoteController.setCommand(0, lightOnCommand, lightOffCommand);

        Log.i("MainActivity", "-------按下灯开的按钮-----");
        remoteController.onButtonWasPushed(0);

        Log.i("MainActivity", "-------按下灯关的按钮-----");
        remoteController.offButtonWasPushed(0);

        Log.i("MainActivity", "-------按下灯撤销的按钮-----");
        remoteController.undoButtonWasPushed();


        TvReceiver tvReceiver = new TvReceiver();
        TvOnCommand tvOnCommand  = new TvOnCommand(tvReceiver);
        TvOffCommand tvOffCommand = new TvOffCommand(tvReceiver);
        remoteController.setCommand(1, tvOnCommand, tvOffCommand);

        Log.i("MainActivity", "-------按下电视开的按钮-----");
        remoteController.onButtonWasPushed(1);

        Log.i("MainActivity", "-------按下电视关的按钮-----");
        remoteController.offButtonWasPushed(1);

        Log.i("MainActivity", "-------按下电视撤销的按钮-----");
        remoteController.undoButtonWasPushed();
    }

    //访问者模式--visitor
    public void onClick22(View view) {
        ObjectStructure successOs = new ObjectStructure();
        ObjectStructure failOs = new ObjectStructure();

        successOs.attach(new Man("郭靖"));
        successOs.attach(new Woman("黄蓉"));

        failOs.attach(new Woman("小龙女"));
        failOs.attach(new Woman("李莫愁"));

        Success success = new Success();
        Fail fail = new Fail();

        successOs.display(success);
        failOs.display(fail);
    }

    //迭代器模式--iterator
    public void onClick23(View view) {
        List<TCollege> tCollegeList = new ArrayList<>();

        TComputerCollege tComputerCollege = new TComputerCollege();
        TInfoCollege tInfoCollege = new TInfoCollege();

        tCollegeList.add(tComputerCollege);
        tCollegeList.add(tInfoCollege);

        OutputImpl output = new OutputImpl(tCollegeList);
        output.printCollege();
    }

    //观察者模式--observer
    public void onClick24(View view) {
        //创建被观察者
        WeatherData weatherData = new WeatherData();
        //创建两个观察者
        CureentConditions cureentConditions = new CureentConditions();
        BaiduConditions baiduConditions = new BaiduConditions();

        weatherData.registerObserver(cureentConditions);
        weatherData.registerObserver(baiduConditions);

        weatherData.setData(11f, 12f, 13f);

        weatherData.removeObserver(baiduConditions);

        weatherData.setData(22f, 23f, 24f);

    }

    //中介者模式--mediator
    public void onClick25(View view) {
        Mediator mediator = new ConcreteMediator();
        Alarm alarm = new Alarm(mediator, "alarm");
        Curtains curtains = new Curtains(mediator, "curtains");

        alarm.sendAlarm(0);
        alarm.sendAlarm(1);

    }

    //备忘录模式--memento
    public void onClick26(View view) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.setState("状态1");

        caretaker.add(originator.saveStateMemento());

        originator.setState("状态2");

        caretaker.add(originator.saveStateMemento());

        Log.i("MainActivity", "-----恢复到状态1前：" + originator.getState());
        originator.getStateFromMemento(caretaker.get(0));
        Log.i("MainActivity", "-----恢复到状态1后：" + originator.getState());


    }

    //解释器模式--interpreter
    public void onClick27(View view) {
        Expression robert = new TerminalExpression("Robert");
        Expression john = new TerminalExpression("John");
        Expression isMale = new OrExpression(robert, john);

        Expression julie = new TerminalExpression("Julie");
        Expression married = new TerminalExpression("Married");
        Expression isMarriedWoman =  new AndExpression(julie, married);

        Log.i("MainActivity", "John is male? " + isMale.interpret("John"));
        Log.i("MainActivity", "Julie is a married women? "
                + isMarriedWoman.interpret("Married Julie"));
    }

    //状态模式--sate
    public void onClick28(View view) {
        RaffleAction action = new RaffleAction(1);
        for(int i = 0; i < 30; i++) {
            Log.i("MainActivity", "-----第" + i + "次抽奖");
            //第一步扣除积分
            action.debuctMoney();
            //第二步抽奖
            action.raffle();
        }
    }

    //策略模式--strategy
    public void onClick29(View view) {
        WildDuck wildDuck = new WildDuck();
        wildDuck.display();
        wildDuck.swim();
        wildDuck.fly();
        wildDuck.quack();
        Log.i("MainActivity", "-------------------");


        PekingDuck pekingDuck = new PekingDuck();
        pekingDuck.display();
        pekingDuck.swim();
        pekingDuck.fly();
        pekingDuck.quack();
        Log.i("MainActivity", "-------------------");

        ToyDuck toyDuck = new ToyDuck();
        toyDuck.display();
        toyDuck.swim();
        toyDuck.fly();
        toyDuck.quack();

        //可以动态改变策略模式
        Log.i("MainActivity", "---动态改变策略---让玩具鸭非得很好---");
        toyDuck.setFlyBehavior(new GoodFlyBehavior());
        toyDuck.fly();

    }
    //职责链模式--chain
    public void onClick30(View view) {
        PurchaseRequest purchaseRequest = new PurchaseRequest(1, 30001, 1);

        DepartmentApprover departmentApprover = new DepartmentApprover("张主任");
        CollegeApprover collegeApprover = new CollegeApprover("李院长");
        ViceSchoolApprover viceSchoolApprover = new ViceSchoolApprover("王副校长");
        SchoolApprover schoolApprover = new SchoolApprover("陈校长");

        departmentApprover.setApprover(collegeApprover);
        collegeApprover.setApprover(viceSchoolApprover);
        viceSchoolApprover.setApprover(schoolApprover);
        schoolApprover.setApprover(departmentApprover); //一定要加这句才能形成环形

        departmentApprover.processRequest(purchaseRequest);


        //形成了环形，这种情况也能找的正确的处理
        purchaseRequest = new PurchaseRequest(2, 3001, 2);
        viceSchoolApprover.processRequest(purchaseRequest);

    }



}
